"""
cloud.py实现云计算相关请求，包括：
1. 镜像上传
2. 实例创建
3. 实例状态查询
4. 实例关机
5. 实例回收
6. 下发实例
7. 生成镜像
"""

import os
from django.conf import settings
import random

from tencentcloud.common import credential
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
# 导入对应产品模块的client models。
from tencentcloud.cvm.v20170312 import cvm_client, models
from tencentcloud.ecm.v20190719 import ecm_client, models as ecm_models

# 导入腾讯对象存储工具
from qcloud_cos import CosConfig
from qcloud_cos import CosS3Client
from sts.sts import Sts

region = 'ap-beijing'
region1= 'ap-beijing'
secret_id = settings.TENCENTCLOUD_SECRET_ID
secret_key = settings.TENCENTCLOUD_SECRET_KEY
cred = credential.Credential(secret_id, secret_key)
endpoint = 'cos.ap-beijing.myqcloud.com'
bucket = 'beijing-1306286147'
# 实例化要请求产品(以cvm为例)的client对象，clientProfile是可选的。
client = cvm_client.CvmClient(cred, region)
emc_client_obj = ecm_client.EcmClient(cred, region)


config = CosConfig(Region=region1, SecretId=secret_id, SecretKey=secret_key, Endpoint=endpoint)
# 2. 获取对象存储客户端对象
cos_client = CosS3Client(config)

instStatus = {
  'UNCREATED': '未创建',
  'PENDING': '操作中..',
  'LAUNCH_FAILED': '创建失败',
  'RUNNING': '运行中..',
  'STOPPED': '关机',
  'STARTING': '开机中..',
  'STOPPING': '关机中..',
  'REBOOTING': '重启中..',
  'SHUTDOWN': '停止待销毁',
  'TERMINATING': '销毁中..'
}

class CloudImage():

    def __init__(self, imageid="", imageurl=""):
        self.imageid = imageid
        self.imageurl = imageurl

    # 上传镜像文件到COS
    def uploadImage(self, file, key):
        # upload 
        print("file: {} key:{} cos_client:{}".format(file, key, cos_client))
        with open(file, 'rb') as fp:
            response = cos_client.put_object(
                Bucket=bucket,
                Body=fp,
                Key=key,
                StorageClass='STANDARD',
                EnableMD5=False
            )
        print(response)
        return response

    def upload(self, file, key):
        # upload image
        with open(file, 'rb') as fp:
            response = cos_client.put_object(
                Bucket=bucket,
                Body=fp,
                Key=key,
                StorageClass='STANDARD',
                EnableMD5=False
            )
        print(response['ETag'])
        return "http://test.com/test"
    
    # 导入镜像
    def importImage(self, ImageName, OsType, OsVersion, ImageUrl, ImageDescription='', Architecture='x86_64'):
        req = models.ImportImageRequest()
        req.Architecture = Architecture
        req.ImageName = ImageName
        req.ImageDescription = ImageDescription
        req.OsType = OsType
        req.OsVersion = OsVersion
        req.ImageUrl = ImageUrl
        req.Force = True
        resp = client.ImportImage(req)
        return resp

    def issue(self, image):
        req = models.RunInstancesRequest()
        req.ImageId = image.imageId
        req.InstanceChargeType = 'POSTPAID_BY_HOUR'
        # req.InstanceType = 'S5.SMALL2'
        req.InstanceType = 'S5.MEDIUM4'
        req.InstanceName = image.image_name
        placement = models.Placement()
        # placement.zone = random.choice(['ap-chengdu-2', 'ap-chengdu-1'])
        # placement.zone ='ap-chengdu-1'
        # placement.zone = random.choice(['ap-beijing-3','ap-beijing-4','ap-beijing-5'])
        placement.zone = random.choice(['ap-beijing-6','ap-beijing-7'])
        req.Placement = placement
        disk = models.DataDisk()
        disk.DiskSize = 100
        disk.DiskType = 'CLOUD_PREMIUM'
        req.DataDisks=[disk]
        systemDisk = models.SystemDisk()
        systemDisk.DiskSize=100
        systemDisk.DiskType='CLOUD_PREMIUM'
        req.SystemDisk = systemDisk
        InternetAccessible = models.InternetAccessible()
        InternetAccessible.InternetChargeType = 'TRAFFIC_POSTPAID_BY_HOUR'
        InternetAccessible.InternetMaxBandwidthOut = 20
        InternetAccessible.PublicIpAssigned = True
        req.InternetAccessible = InternetAccessible
        LoginSetting = models.LoginSettings()
        LoginSetting.KeepImageLogin = "True"
        req.LoginSettings = LoginSetting
        req.SecurityGroupIds = ['sg-qwfyaoy9']

        resp = client.RunInstances(req)
        return resp.InstanceIdSet[0]

    def issueBatch(self, image, inst_count):
        req = models.RunInstancesRequest()
        req.ImageId = image.imageId
        req.InstanceChargeType = 'POSTPAID_BY_HOUR'
        # req.InstanceType = 'S5.SMALL2'
        req.InstanceType = 'S5.MEDIUM4'
        if inst_count > 0:
            req.InstanceCount = inst_count

        req.InstanceName = image.image_name
        placement = models.Placement()
        # placement.zone = random.choice(['ap-chengdu-2', 'ap-chengdu-1'])
        # placement.zone ='ap-chengdu-1'
        # placement.zone = random.choice(['ap-beijing-3', 'ap-beijing-4', 'ap-beijing-5'])
        placement.zone = random.choice(['ap-beijing-6', 'ap-beijing-7'])
        req.Placement = placement
        disk = models.DataDisk()
        disk.DiskSize = 100
        disk.DiskType = 'CLOUD_PREMIUM'
        req.DataDisks = [disk]
        systemDisk = models.SystemDisk()
        systemDisk.DiskSize = 100
        systemDisk.DiskType = 'CLOUD_PREMIUM'
        req.SystemDisk = systemDisk
        InternetAccessible = models.InternetAccessible()
        InternetAccessible.InternetChargeType = 'TRAFFIC_POSTPAID_BY_HOUR'
        InternetAccessible.InternetMaxBandwidthOut = 20
        InternetAccessible.PublicIpAssigned = True
        req.InternetAccessible = InternetAccessible
        LoginSetting = models.LoginSettings()
        LoginSetting.KeepImageLogin = "True"
        req.LoginSettings = LoginSetting
        req.SecurityGroupIds = ['sg-qwfyaoy9']

        resp = client.RunInstances(req)
        return resp.InstanceIdSet

    # 获取可用镜像列表
    def describeImages(self, respFilter):
        req = models.DescribeImagesRequest()
        req.Filters = respFilter
        # if len(kwargs) > 0:
        #     req.Filters = []
        #     for k in kwargs:
        #         respFilter = models.Filter()  # 创建Filter对象
        #         respFilter.Name = k
        #         respFilter.Values = kwargs[k]
        #         req.Filters.append(respFilter)

        resp = client.DescribeImages(req)
        return resp
    def describeImagesByName(self, ImageName):
        req = models.DescribeImagesRequest()
        Filter = models.Filter()
        Filter.Name = 'image-name'
        Filter.Values = [ImageName]
        req.Filters = [Filter]
        return client.DescribeImages(req)
    def describeImagesByID(self, ImageID):
        req = models.DescribeImagesRequest()
        req.ImageIds = [ImageID]
        resp = client.DescribeImages(req)
        if resp.TotalCount > 0:
            return resp.ImageSet[0]
        return None

    # 查询导入状态
    def DescribeCustomImageTask(self, ImageName):
        req = ecm_models.DescribeCustomImageTaskRequest()
        respFilter = models.Filter()
        respFilter.Name = 'image-name'
        respFilter.Values = [ImageName]
        req.Filters = [respFilter]
        print(respFilter)
        return emc_client_obj.DescribeCustomImageTask(req)
    
    def DescribeInstanceVncUrl(self, InsId):
        req = models.DescribeInstanceVncUrlRequest()
        req.InstanceId = InsId
        resp = client.DescribeInstanceVncUrl(req)
        print(resp)
        return 'https://img.qcloud.com/qcloud/app/active_vnc/index.html?InstanceVncUrl=' + resp.InstanceVncUrl

class CloudInstance():

    def __init__(self, instanceid=""):
        self.instanceid = instanceid

    def batch_create(self):
        return True
    # 注：所有调用 clound.py 接口必须捕获 except TencentCloudSDKException as err 异常
    # InternetAccessible 公网带宽信息
    # SystemDisk 系统盘配置
    # DataDisks 磁盘配置
    def create(self, ImageId, InstanceType, InstanceName, Placement, DataDisks, SystemDisk, InternetAccessible):
        req = models.RunInstancesRequest()
        req.ImageId = ImageId
        req.InstanceChargeType = 'POSTPAID_BY_HOUR'
        req.InstanceType = InstanceType
        req.InstanceName = InstanceName
        req.Placement = Placement
        req.DataDisks = DataDisks
        req.SystemDisk = SystemDisk
        resp = client.RunInstances(req)
        return resp

    def get_status(self):
        return 1

    def createImage(self, instanceId, imageName, note):
        req = models.CreateImageRequest()
        req.InstanceId = instanceId
        req.ImageName = imageName
        req.ImageDescription = note
        req.ForcePoweroff = "TRUE"
        print(req)
        resp = client.CreateImage(req)
        return resp

    def deleteImages(self, imageIds):
        req = models.DeleteImagesRequest()
        req.ImageIds = imageIds
        resp = client.DeleteImages(req)
        return resp

    def deleteImage(self, imageId):
        return self.deleteImages([imageId])

    # 关闭实例
    def shutdown(self, instanceIds):
      req = models.StopInstancesRequest()
      req.InstanceIds = instanceIds
      req.ForceStop = True
      resp = client.StopInstances(req)
      return resp
    
    # 退还实例
    def terminateInstances(self, InstanceIds):
        req = models.TerminateInstancesRequest()
        req.InstanceIds = InstanceIds
        resp = client.TerminateInstances(req)
        return resp

    # 查看实例列表
    def DescribeInstances(self, InstanceIds, Filters, Offset, Limit):
        req = models.DescribeInstancesRequest()
        req.InstanceIds = InstanceIds
        req.Filters = Filters
        req.Offset = Offset
        req.Limit = Limit
        resp = client.DescribeInstances(req)
        return resp
    
    def DescribeInstance(self, InstanceId):
        req = models.DescribeInstancesRequest()
        req.InstanceIds = [InstanceId]
        resp = client.DescribeInstances(req)
        print(resp)
        if resp.TotalCount == 0:
            return None
        return resp.InstanceSet[0]

    def DescribeInstanceVncUrl(self, InsId):
        req = models.DescribeInstanceVncUrlRequest()
        req.InstanceId = InsId
        resp = client.DescribeInstanceVncUrl(req)
        print(resp)
        return 'https://img.qcloud.com/qcloud/app/active_vnc/index.html?InstanceVncUrl=' + resp.InstanceVncUrl

    def recovery(self, InstanceIds):
        req = models.TerminateInstancesRequest()
        req.InstanceIds = InstanceIds
        resp = client.TerminateInstances(req)
        print (resp)
        return resp.RequestId is not None

    def start(self, InstanceIds):
        req = models.StartInstancesRequest()
        req.InstanceIds = InstanceIds
        resp = client.StartInstances(req)
        print (resp)
        return resp.RequestId is not None

    def save(self):
        return "img-0yc6rie8"

    def batch_shutdown(self, instanceIds):
      req = models.StopInstancesRequest()
      req.InstanceIds = instanceIds
      req.ForceStop = True
      req.StoppedMode = 'STOP_CHARGING'
      resp = client.StopInstances(req)
      return resp

class CosClient():
    def get_presigned_url(self, Key):
        return cos_client.get_presigned_url(bucket, Key, 'GET', Expired=3000)

    def get_credential(self):
        config = {
            # 'url': 'https://sts.tencentcloudapi.com/',
            # 'domain': 'sts.tencentcloudapi.com',
            # 临时密钥有效时长，单位是秒
            'duration_seconds': 7200,
            'secret_id': secret_id,
            # 固定密钥
            'secret_key': secret_key,
            # 换成你的 bucket
            'bucket': bucket,
            # 换成 bucket 所在地区
            'region': region1,
            # 这里改成允许的路径前缀，可以根据自己网站的用户登录态判断允许上传的具体路径
            # 例子： a.jpg 或者 a/* 或者 * (使用通配符*存在重大安全风险, 请谨慎评估使用)
            'allow_prefix': '*',
            # 密钥的权限列表。简单上传和分片需要以下的权限，其他权限列表请看 https://cloud.tencent.com/document/product/436/31923
            'allow_actions': [
                # 简单上传
                '*',
                'name/cos/*',
                'name/cos:PutObject',
                'name/cos:PostObject',
                'name/cos:GetObject',
                'name/cos:GetService',
                'name/cos:GetBucket',
                # 分片上传
                'name/cos:InitiateMultipartUpload',
                'name/cos:ListMultipartUploads',
                'name/cos:ListParts',
                'name/cos:UploadPart',
                'name/cos:CompleteMultipartUpload'
            ],

        }
        try:
            sts = Sts(config)
            response = sts.get_credential()
            return response
        except Exception as e:
            print(e)
            return None
